#pragma once

#include "base.h"

namespace cgen {
namespace internal {

// ----------------------------------------------------------------------------
// A Handle provides a reference to an object that survives relocation by
// the garbage collector.
// Handles are only valid within a HandleScope.
// When a handle is created for an object a cell is allocated in the heap.

template<class T>
class Handle
{
public:
    INLINE(Handle(T** location)) { location_ = location; }
    INLINE(explicit Handle(T* obj));

    INLINE(Handle()) : location_(NULL) {}

    // Constructor for handling automatic up casting.
    // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
    template <class S> Handle(Handle<S> handle)
    {
#ifdef DEBUG
        T* a = NULL;
        S* b = NULL;
        a = b;  // Fake assignment to enforce type checks.
        USE(a);
#endif
        location_ = reinterpret_cast<T**>(handle.location());
    }

    INLINE(T* operator ->() const) { return operator*(); }

    // Check if this handle refers to the exact same object as the other handle.
    bool is_identical_to(const Handle<T> other) const
    {
        return operator*() == *other;
    }

    // Provides the C++ dereference operator.
    INLINE(T* operator*() const);

    // Returns the address to where the raw pointer is stored.
    T** location() const
    {
        ASSERT(location_ == NULL || reinterpret_cast<Address>(*location_) != kZapValue);
        return location_;
    }

    template <class S> static Handle<T> cast(Handle<S> that)
    {
        T::cast(*that);
        return Handle<T>(reinterpret_cast<T**>(that.location()));
    }

    static Handle<T> null()
    { return Handle<T>(); }

    bool is_null() const
    { return location_ == NULL; }

#if 0
  // Closes the given scope, but lets this handle escape. See
  // implementation in api.h.
  inline Handle<T> EscapeFrom(v8::HandleScope* scope);
#endif

private:
    T** location_;
};

}} // namespace cgen::internal
